﻿using Mapster;
using MathNet.Numerics.Differentiation;
using Microsoft.AspNetCore.Http.Connections;
using Microsoft.Extensions.DependencyInjection;
using SqlSugar;
using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using System.Text;
using System.Threading.Tasks;
using XW.Utils; 

namespace XW.Core;

public static class SqlSugarServiceExtent
{
    /// <summary>
    /// SqlSugar 上下文初始化
    /// </summary>
    /// <param name="services"></param>
    public static void AddSqlSugar(this IServiceCollection services)
    {
        // 自定义 SqlSugar 雪花ID算法
        SnowFlakeSingle.WorkId = ConfigHelper.GetInt("Snow:WorkerId");
        

        var sysConfig = ConfigHelper.GetConn("sys");
        //dbOptions.ConnectionConfigs.ForEach(SetDbConfig);
        var config = new ConnectionConfig {
             ConfigId = App.DB_DEFAULT_CONN_NAME,
             ConnectionString = sysConfig,
             DbType = DbType.MySql,

        };
        SetDbConfig(config);
        SqlSugarScope sqlSugar = new(config, db =>
        {
            SetDbAop(db);
            //config.ForEach(config =>
            //{
            //    var dbProvider = db.GetConnectionScope(config.ConfigId);
            //    SetDbAop(dbProvider);
            //    //SetDbDiffLog(dbProvider, config);
            //});
        });

        services.AddSingleton<ISqlSugarClient>(sqlSugar); // 单例注册
        services.AddScoped(typeof(SqlSugarRepository<>)); // 仓储注册
                                                          // services.AddUnitOfWork<SqlSugarUnitOfWork>(); // 事务与工作单元注册

        // 初始化数据库表结构及种子数据
        InitDatabase(sqlSugar, config);
    }
    /// <summary>
    /// 配置Aop
    /// </summary>
    /// <param name="db"></param>
    public static void SetDbAop(SqlSugarClient db)
    {
        var config = db.CurrentConnectionConfig;

        // 设置超时时间
        db.Ado.CommandTimeOut = 30;

        // 打印SQL语句
        db.Aop.OnLogExecuting = (sql, pars) =>
        {
            var originColor = Console.ForegroundColor;
            if (sql.StartsWith("SELECT", StringComparison.OrdinalIgnoreCase))
                Console.ForegroundColor = ConsoleColor.Green;
            if (sql.StartsWith("UPDATE", StringComparison.OrdinalIgnoreCase) || sql.StartsWith("INSERT", StringComparison.OrdinalIgnoreCase))
                Console.ForegroundColor = ConsoleColor.Yellow;
            if (sql.StartsWith("DELETE", StringComparison.OrdinalIgnoreCase))
                Console.ForegroundColor = ConsoleColor.Red;
            Console.WriteLine("【" + DateTime.Now + "——执行SQL】\r\n" + UtilMethods.GetSqlString(config.DbType, sql, pars) + "\r\n");
            Console.ForegroundColor = originColor;
            //App.PrintToMiniProfiler("SqlSugar", "Info", sql + "\r\n" + db.Utilities.SerializeObject(pars.ToDictionary(it => it.ParameterName, it => it.Value)));
        };
        db.Aop.OnError = ex =>
        {
            if (ex.Parametres == null) return;
            var originColor = Console.ForegroundColor;
            Console.ForegroundColor = ConsoleColor.DarkRed;
            var pars = db.Utilities.SerializeObject(((SugarParameter[])ex.Parametres).ToDictionary(it => it.ParameterName, it => it.Value));
            Console.WriteLine("【" + DateTime.Now + "——错误SQL】\r\n" + UtilMethods.GetSqlString(config.DbType, ex.Sql, (SugarParameter[])ex.Parametres) + "\r\n");
            Console.ForegroundColor = originColor;
            //App.PrintToMiniProfiler("SqlSugar", "Error", $"{ex.Message}{Environment.NewLine}{ex.Sql}{pars}{Environment.NewLine}");
        };
        db.Aop.OnLogExecuted = (sql, pars) =>
        {
            // 执行时间超过5秒
            if (db.Ado.SqlExecutionTime.TotalSeconds > 5)
            {
                var fileName = db.Ado.SqlStackTrace.FirstFileName; // 文件名
                var fileLine = db.Ado.SqlStackTrace.FirstLine; // 行号
                var firstMethodName = db.Ado.SqlStackTrace.FirstMethodName; // 方法名
                var log = $"【所在文件名】：{fileName}\r\n【代码行数】：{fileLine}\r\n【方法名】：{firstMethodName}\r\n" + $"【sql语句】：{UtilMethods.GetSqlString(config.DbType, sql, pars)}";
                var originColor = Console.ForegroundColor;
                Console.ForegroundColor = ConsoleColor.DarkYellow;
                Console.WriteLine(log);
                Console.ForegroundColor = originColor;
            }
        };
        // 数据审计
        db.Aop.DataExecuting = (oldValue, entityInfo) =>
        {
            //// 演示环境判断
            //if (entityInfo.EntityColumnInfo.IsPrimarykey)
            //{
            //    if (entityInfo.EntityName != nameof(SysJobDetail) && entityInfo.EntityName != nameof(SysJobTrigger) &&
            //        entityInfo.EntityName != nameof(SysLogOp) && entityInfo.EntityName != nameof(SysLogVis) &&
            //        entityInfo.EntityName != nameof(SysOnlineUser))
            //    {
            //        var isDemoEnv = App.GetService<SysConfigService>().GetConfigValue<bool>(CommonConst.SysDemoEnv).GetAwaiter().GetResult();
            //        if (isDemoEnv)
            //            throw Oops.Oh(ErrorCodeEnum.D1200);
            //    }
            //}

            if (entityInfo.OperationType == DataFilterType.InsertByObject)
            {
                // 主键(long类型)且没有值的---赋值雪花Id
                if (entityInfo.EntityColumnInfo.IsPrimarykey && entityInfo.EntityColumnInfo.PropertyInfo.PropertyType == typeof(long))
                {
                    var id = entityInfo.EntityColumnInfo.PropertyInfo.GetValue(entityInfo.EntityValue);
                    if (id == null || (long)id == 0)
                        entityInfo.SetValue(SnowFlakeSingle.Instance.NextId());
                }
                if (entityInfo.PropertyName == "CreateTime")
                    entityInfo.SetValue(DateTime.Now);
                var userId = CommonHelper.GetUserId();

				if (userId >0)
                {
                    //if (entityInfo.PropertyName == "TenantId")
                    //{
                    //    var tenantId = ((dynamic)entityInfo.EntityValue).TenantId;
                    //    if (tenantId == null || tenantId == 0)
                    //        entityInfo.SetValue(App.User.FindFirst(ClaimConst.TenantId)?.Value);
                    //}
                    if (entityInfo.PropertyName == "CreateUserId")
                    {
                        var createUserId = ((dynamic)entityInfo.EntityValue).CreateUserId;
                        if (createUserId == 0 || createUserId == null)
                            entityInfo.SetValue(userId);
                    }

                    //if (entityInfo.PropertyName == "CreateOrgId")
                    //{
                    //    var createOrgId = ((dynamic)entityInfo.EntityValue).CreateOrgId;
                    //    if (createOrgId == 0 || createOrgId == null)
                    //        entityInfo.SetValue(App.User.FindFirst(ClaimConst.OrgId)?.Value);
                    //}
                }
            }
            if (entityInfo.OperationType == DataFilterType.UpdateByObject)
            {
                if (entityInfo.PropertyName == "UpdateTime")
                    entityInfo.SetValue(DateTime.Now);
                if (entityInfo.PropertyName == "UpdateUserId")
                    entityInfo.SetValue(CommonHelper.GetUserId());
            }
        };

        //// 超管时排除各种过滤器
        //if (App.User?.FindFirst(ClaimConst.AccountType)?.Value == ((int)AccountTypeEnum.SuperAdmin).ToString())
        //    return;

        //// 配置实体假删除过滤器
        //db.QueryFilter.AddTableFilter<IDeletedFilter>(u => u.IsDelete == false);
        //// 配置租户过滤器
        //var tenantId = App.User?.FindFirst(ClaimConst.TenantId)?.Value;
        //if (!string.IsNullOrWhiteSpace(tenantId))
        //    db.QueryFilter.AddTableFilter<ITenantIdFilter>(u => u.TenantId == long.Parse(tenantId));

        //// 配置用户机构（数据范围）过滤器
        //SqlSugarFilter.SetOrgEntityFilter(db);
        //// 配置自定义过滤器
        //SqlSugarFilter.SetCustomEntityFilter(db);
    }
    /// <summary>
    /// 配置连接属性
    /// </summary>
    /// <param name="config"></param>
    public static void SetDbConfig(ConnectionConfig config)
    {
        var configureExternalServices = new ConfigureExternalServices
        {
            EntityNameService = (type, entity) => // 处理表
            {
                entity.IsDisabledDelete = true; // 禁止删除非 sqlsugar 创建的列
                // 只处理贴了特性[SugarTable]表
                if (!type.GetCustomAttributes<SugarTable>().Any())
                    return;
                if ( !entity.DbTableName.Contains('_'))
                    entity.DbTableName = UtilMethods.ToUnderLine(entity.DbTableName); // 驼峰转下划线
            },
            EntityService = (type, column) => // 处理列
            {
                // 只处理贴了特性[SugarColumn]列
                if (!type.GetCustomAttributes<SugarColumn>().Any())
                    return;
                if (new NullabilityInfoContext().Create(type).WriteState is NullabilityState.Nullable)
                    column.IsNullable = true;
                if ( !column.IsIgnore && !column.DbColumnName.Contains('_'))
                    column.DbColumnName = UtilMethods.ToUnderLine(column.DbColumnName); // 驼峰转下划线

                //if (config.DbType == SqlSugar.DbType.Oracle)
                //{
                //    if (type.PropertyType == typeof(long) || type.PropertyType == typeof(long?))
                //        column.DataType = "number(18)";
                //    if (type.PropertyType == typeof(bool) || type.PropertyType == typeof(bool?))
                //        column.DataType = "number(1)";
                //}
            },
            DataInfoCacheService = new SqlSugarCache(),
        };
        config.ConfigureExternalServices = configureExternalServices;
        config.InitKeyType = InitKeyType.Attribute;
        config.IsAutoCloseConnection = true;
        config.MoreSettings = new ConnMoreSettings
        {
            IsAutoRemoveDataCache = true,
            IsAutoDeleteQueryFilter = true, // 启用删除查询过滤器
            IsAutoUpdateQueryFilter = true, // 启用更新查询过滤器
            SqlServerCodeFirstNvarchar = true // 采用Nvarchar
        };
    }

    /// <summary>
    /// 初始化数据库
    /// </summary>
    /// <param name="db"></param>
    /// <param name="config"></param>
    private static void InitDatabase(SqlSugarScope db, ConnectionConfig config)
    {
        SqlSugarScopeProvider dbProvider = db.GetConnectionScope(config.ConfigId);

        //// 初始化/创建数据库
        //if (config.DbSettings.EnableInitDb)
        //{
        //    if (config.DbType != SqlSugar.DbType.Oracle)
        //        dbProvider.DbMaintenance.CreateDatabase();
        //}

        // 初始化表结构
        if (ConfigHelper.GetAppBool("InitTable",false))
        {
            var entiryTypes1 = ReflectionHelper.FindClassesOfType<IEntity>();
            var entityTypes = entiryTypes1.Where(u => !u.IsInterface && !u.IsAbstract && u.IsClass && u.IsDefined(typeof(SugarTable), false)).ToList();
            if (entityTypes.Any())
            {
                foreach (var entityType in entityTypes)
                {
                    var tAtt = entityType.GetCustomAttribute<TenantAttribute>();
                    if (tAtt != null && tAtt.configId.ToString() != config.ConfigId) continue;
                    if (tAtt == null && config.ConfigId != App.DB_DEFAULT_CONN_NAME) continue;

                    if (entityType.GetCustomAttribute<SplitTableAttribute>() == null)
                        dbProvider.CodeFirst.InitTables(entityType);
                    else
                        dbProvider.CodeFirst.SplitTables().InitTables(entityType);
                }
            }
        }

        // 初始化种子数据
        if (ConfigHelper.GetAppBool("EnableInitSeed", false))
        {
            var seedTypes = ReflectionHelper.FindClassesOfType(typeof(ISeedDataEntity<>));
            var seedDataTypes = seedTypes.Where(u => !u.IsInterface && !u.IsAbstract && u.IsClass).ToList();
            if (seedDataTypes.Any())
            {
                foreach (var seedType in seedDataTypes)
                {
                    var entiry = Activator.CreateInstance(seedType);
                    var hasDataMethod = seedType.GetMethod("GetSeedData");
                    var seedDatas = ((IEnumerable)hasDataMethod?.Invoke(entiry, null))?.Cast<object>();
                    if (seedDatas == null) continue;

                    var entityType = seedType.GetInterfaces().First().GetGenericArguments().First();

                    var entityInfo = dbProvider.EntityMaintenance.GetEntityInfo(entityType);

                    // 按主键进行批量增加和更新
                    // 无主键则只进行插入
                    if (!dbProvider.Queryable(entityInfo.DbTableName, entityInfo.DbTableName).Any())
                        dbProvider.InsertableByObject(seedDatas.ToList()).ExecuteCommand();
                }
            }
        }
         
    }

    ///// <summary>
    ///// 初始化租户业务数据库
    ///// </summary>
    ///// <param name="iTenant"></param>
    ///// <param name="config"></param>
    //public static void InitTenantDatabase(ITenant iTenant, DbConnectionConfig config)
    //{
    //    SetDbConfig(config);

    //    iTenant.AddConnection(config);
    //    var db = iTenant.GetConnectionScope(config.ConfigId);
    //    db.DbMaintenance.CreateDatabase();

    //    //// 获取所有实体表-初始化租户业务表
    //    //var entityTypes = App.EffectiveTypes.Where(u => !u.IsInterface && !u.IsAbstract && u.IsClass
    //    //    && u.IsDefined(typeof(SugarTable), false) && !u.IsDefined(typeof(SystemTableAttribute), false)).ToList();
    //    //if (!entityTypes.Any()) return;
    //    //foreach (var entityType in entityTypes)
    //    //{
    //    //    var splitTable = entityType.GetCustomAttribute<SplitTableAttribute>();
    //    //    if (splitTable == null)
    //    //        db.CodeFirst.InitTables(entityType);
    //    //    else
    //    //        db.CodeFirst.SplitTables().InitTables(entityType);
    //    //}
    //}
}
